package c2.cross.business.boss.data;

import cate.common.table.cross_boss.base.CrossBossFarmBaseRow;
import cate.common.util.TimeTool;
import cate.game.farm.local.cross_boss.data.CrossBossDetailVO;
import cate.game.farm.local.cross_boss.data.CrossBossRank;
import cate.game.farm.local.cross_boss.data.CrossBossSimpleVO;
import cate.game.role.RoleSnapshot;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.springframework.data.annotation.Transient;

import java.util.*;

@NoteClass("单个BOSS数据")
public class CrossBossSingleData {
    @NoteField("BOSS配置ID")
    public int id;
    @NoteField("BOSS当前血量")
    public long curHp;
    @NoteField("排行数据")
    public List<CrossBossRank> rankList;
    @NoteField("重置时间")
    public long resetTime;

    @JsonIgnore
    @Transient
    @NoteField("锁定解除打点")
    public int lockEndTick;

    /**
     * 初始化
     */
    public void init() {
        if (rankList == null) {
            rankList = new ArrayList<>();
        }
    }

    /**
     * BOSS是否死亡
     */
    public boolean dead() {
        return curHp <= 0;
    }

    /**
     * 锁定并获取BOSS当前血量
     */
    public synchronized long getCurHpAndLock() {
        if (lockEndTick > 0) {
            return -1;
        }
        lockEndTick = 5;
        return curHp;
    }

    /**
     * 更新玩家伤害
     *
     * @param roleSnapshot 玩家快照
     * @param damage 伤害量
     * @param row 配置项
     * @return 是否击杀
     */
    public synchronized boolean updateRoleDamage(RoleSnapshot roleSnapshot, long damage, CrossBossFarmBaseRow row) {
        lockEndTick = 0;
        if (dead()) {
            return false;
        }
        if (damage >= 0) {
            curHp = Math.max(0, curHp - damage);
            Optional<CrossBossRank> op = rankList.stream().filter(rank -> rank.owner.uid.equals(roleSnapshot.uid)).findAny();
            if (op.isPresent()) {
                CrossBossRank rank = op.get();
                rank.owner = roleSnapshot;
                rank.value += damage;
                rank.recordTime = System.currentTimeMillis();
            } else {
                CrossBossRank rank = new CrossBossRank();
                rank.owner = roleSnapshot;
                rank.value = damage;
                rank.recordTime = System.currentTimeMillis();
                rankList.add(rank);
            }
            rankList.sort(Comparator.comparing(CrossBossRank::getValue)
                    .reversed()
                    .thenComparing(CrossBossRank::getRecordTime));
            if (dead()) {
                resetTime = System.currentTimeMillis() + row.resetTimeSec * TimeTool.TimeCons.SECOND;
            }
        }
        return dead();
    }

    /**
     * 循环
     *
     * @param nowTime 当前时间
     * @param row 配置项
     * @return 是否触发了重置
     */
    public synchronized boolean tick(long nowTime, CrossBossFarmBaseRow row) {
        if (row == null) {
            return false;
        }
        if (lockEndTick > 0) {
            lockEndTick--;
        }
        if (dead()) {
            if (nowTime >= resetTime) {
                reset(row);
                return true;
            }
        }
        return false;
    }

    /**
     * 重置数据
     *
     * @param row 配置项
     */
    public void reset(CrossBossFarmBaseRow row) {
        curHp = row.maxHp;
        resetTime = 0;
        rankList.clear();
    }

    /**
     * 转简要数据
     */
    public CrossBossSimpleVO toSimple() {
        CrossBossSimpleVO vo = new CrossBossSimpleVO();
        vo.id = id;
        vo.curHp = curHp;
        vo.resetTime = resetTime;
        return vo;
    }

    /**
     * 转详细数据
     *
     * @param uid 角色UID
     */
    public CrossBossDetailVO toDetail(String uid) {
        CrossBossDetailVO vo = new CrossBossDetailVO();
        vo.id = id;
        vo.curHp = curHp;
        vo.resetTime = resetTime;
        vo.rankList = new ArrayList<>(rankList.size() > 100 ? rankList.subList(0, 100) : rankList);
        Optional<CrossBossRank> op = vo.rankList.stream().filter(rank -> rank.owner.uid.equals(uid)).findAny();
        if (op.isPresent()) {
            vo.myRank = vo.rankList.indexOf(op.get()) + 1;
            vo.myDamage = op.get().value;
        } else {
            vo.myRank = -1;
            vo.myDamage = 0;
        }
        return vo;
    }
}
